package com.github.wxiaoqi.security.crm.core.biz;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.wxiaoqi.security.crm.core.entity.Customer;
import com.github.wxiaoqi.security.crm.core.entity.FreezeJournal;
import com.github.wxiaoqi.security.crm.core.entity.MerchantAccount;
import com.github.wxiaoqi.security.crm.core.entity.MerchantAccountJournal;
import com.github.wxiaoqi.security.crm.core.entity.MerchantBase;
import com.github.wxiaoqi.security.crm.core.entity.PersonalAccount;
import com.github.wxiaoqi.security.crm.core.entity.PersonalAccountJournal;
import com.github.wxiaoqi.security.crm.core.entity.PersonalBase;
import com.github.wxiaoqi.security.crm.core.entity.PersonalBilling;
import com.github.wxiaoqi.security.crm.core.entity.UnfreezeJournal;
import com.github.wxiaoqi.security.crm.core.mapper.CustomerMapper;
import com.github.wxiaoqi.security.crm.core.mapper.FreezeJournalMapper;
import com.github.wxiaoqi.security.crm.core.mapper.MerchantAccountJournalMapper;
import com.github.wxiaoqi.security.crm.core.mapper.MerchantAccountMapper;
import com.github.wxiaoqi.security.crm.core.mapper.PersonalAccountJournalExtMapper;
import com.github.wxiaoqi.security.crm.core.mapper.PersonalAccountJournalMapper;
import com.github.wxiaoqi.security.crm.core.mapper.PersonalAccountMapper;
import com.github.wxiaoqi.security.crm.core.mapper.PersonalBaseMapper;
import com.github.wxiaoqi.security.crm.core.mapper.PersonalBillingMapper;
import com.github.wxiaoqi.security.crm.core.mapper.UnfreezeJournalMapper;
import com.github.wxiaoqi.security.auth.common.util.SnowFlake;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.msg.AccountType;
import com.github.wxiaoqi.security.common.msg.CustomerType;
import com.github.wxiaoqi.security.common.msg.ResponseCode;
import com.github.wxiaoqi.security.common.util.EntityUtils;
import com.github.wxiaoqi.security.common.util.MD5;

import lombok.extern.slf4j.Slf4j;

/**
 * 个人账户(冻结账户准入不准出)
 * @author centerroot
 * @email lfw6699@163.com
 * @date 2018-05-25 15:20:48
 */
@Slf4j
@Transactional(rollbackFor = Exception.class)
@Service
public class PersonalAccountBiz extends BaseBiz<PersonalAccountMapper,PersonalAccount> {
	
	@Autowired
	private PlatformAccoutConfigBiz platformAccoutConfigBiz;
	@Autowired
	private CustomerMapper customerMapper;
	@Autowired
	private PersonalBaseMapper personalBaseMapper;
	@Autowired
	private PersonalAccountMapper personalAccountMapper;
	@Autowired
	private PersonalAccountJournalMapper personalAccountJournalMapper;
	@Autowired
	private PersonalAccountJournalExtMapper personalAccountJournalExtMapper;
	@Autowired
	private PersonalBillingMapper personalBillingMapper;
	@Autowired
	private FreezeJournalMapper freezeJournalMapper;
	@Autowired
	private UnfreezeJournalMapper unfreezeJournalMapper;
	@Autowired
	private MerchantAccountMapper merchantAccountMapper;
	@Autowired
	private MerchantAccountBiz merchantAccountBiz;
	@Autowired
	private MerchantAccountJournalMapper merchantAccountJournalMapper;
	@Value("${bountyHunter.balanceSaltValue}")
	private String balanceSaltValue;
	
	/**
	 * 个人账户开户
	 * 成功返回账户号
	 * 入参：perId、accType
	 */
	public Map<String, Object> openAccount(Map<String, Object> param){
		log.info("个人账户开户   请求参数：{}",param);
		Map<String, Object> respMap = new HashMap<String, Object>();
		String platformId = (String) param.get("platformId");
		String perId = (String) param.get("perId");
		String accType = (String) param.get("accType");
		
		PersonalBase personalBase = personalBaseMapper.selectByPrimaryKey(perId);
		if (null == personalBase) {
			respMap.put("code", ResponseCode.MER_NOTEXIST.getCode());
			respMap.put("msg", ResponseCode.MER_NOTEXIST.getMessage());
			return respMap;
		}
		
		param.put("conType", "CON001");
		Map<String, Object> respPlatMap = platformAccoutConfigBiz.isExist(param);
		if (!ResponseCode.OK.getCode().equals(respPlatMap.get("code"))) {
			log.info("企业账户开户   响应参数：{}",respMap);
			return respMap;
		}
		
		PersonalAccount personalAccountReq = new PersonalAccount();
		personalAccountReq.setPerId(perId);
		personalAccountReq.setAccType(accType);
		PersonalAccount personalAccount = personalAccountMapper.selectOne(personalAccountReq);
		
		if (null == personalAccount) {
			personalAccount = new PersonalAccount();
			String accId = String.valueOf(SnowFlake.getId());
			personalAccount.setAccId(accId);
			personalAccount.setAccBalance(new BigDecimal("0.00"));
			personalAccount.setChecksum(MD5.sign(personalAccount.getAccBalance().toString(), balanceSaltValue, "utf-8"));
			personalAccount.setCcy("CNY");
			personalAccount.setAccountStatus("00");
			personalAccount.setPerId(perId);
			personalAccount.setAccType(accType);
			personalAccount.setCreatetime(new Timestamp(System.currentTimeMillis()));
			personalAccountMapper.insert(personalAccount);
		}
		
		respMap.put("personalAccount", personalAccount);
		respMap.put("code", ResponseCode.OK.getCode());
		respMap.put("msg", ResponseCode.OK.getMessage());
		log.info("个人账户开户   响应参数：{}",respMap);
		return respMap;
	}
	
	/**
	 * 个人账户入金
	 * 入参：perId、accType、intoAmt
	 */
	public Map<String, Object> deposit(Map<String, Object> param){
		log.info("个人账户入金   请求参数：{}",param);
		Map<String, Object> respMap = new HashMap<String, Object>();
		String perId = (String) param.get("perId");
		String platformId = (String) param.get("platformId");
		String accType = (String) param.get("accType");
		String orderNo = (String) param.get("orderNo");
		String orderType = (String) param.get("orderType");
		String payWay = (String) param.get("payWay");
		String transferAmtStr = (String) param.get("transferAmt");

		String inflowId = (String) param.get("inflowId");
		String inflowType = (String) param.get("inflowType");
		
		BigDecimal transferAmt = new BigDecimal(transferAmtStr);
		
		Map<String, Object> reqBalMap = new HashMap<String, Object>();
		reqBalMap.put("perId", perId);
		reqBalMap.put("platformId", platformId);
		reqBalMap.put("accType", accType);
		Map<String, Object> openAccMap = openAccount(reqBalMap);
		if (!ResponseCode.OK.getCode().equals(openAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openAccMap);
			return openAccMap;
		}
		PersonalAccount personalAccount = (PersonalAccount) openAccMap.get("personalAccount");
		
		boolean flag = MD5.verify(personalAccount.getAccBalance().toString(), personalAccount.getChecksum(), balanceSaltValue, "utf-8");
		if (flag) {
			personalAccount.setAccBalance(personalAccount.getAccBalance().add(transferAmt));
			personalAccount.setChecksum(MD5.sign(personalAccount.getAccBalance().toString(), balanceSaltValue, "utf-8"));
			personalAccount.setUpdatetime(new Timestamp(System.currentTimeMillis()));
			personalAccountMapper.updateByPrimaryKey(personalAccount);
			
			PersonalAccountJournal personalAccountJournal = new PersonalAccountJournal();
			String perJournalId = String.valueOf(SnowFlake.getId());
			personalAccountJournal.setJournalId(perJournalId);
			personalAccountJournal.setAccId(personalAccount.getAccId());
			personalAccountJournal.setPlatformId(platformId);
			personalAccountJournal.setOrderNo(orderNo);
			personalAccountJournal.setPerId(perId);
			personalAccountJournal.setAccType(accType);
			personalAccountJournal.setInOutFlag("1");//来账
			personalAccountJournal.setTradeAmt(transferAmt);
			personalAccountJournal.setTradeType(orderType);
			personalAccountJournal.setCreatetime(new Timestamp(System.currentTimeMillis()));
			personalAccountJournalMapper.insert(personalAccountJournal);
			
			PersonalBilling personalBilling = new PersonalBilling();
			String billId = String.valueOf(SnowFlake.getId());
			personalBilling.setBillId(billId);
			personalBilling.setPlatformId(platformId);
			personalBilling.setPerId(perId);
			personalBilling.setAccJournalId(perJournalId);
			personalBilling.setOrderNo(orderNo);
			personalBilling.setBillType(orderType);
			personalBilling.setInOutFlag("1");
			personalBilling.setTranAmt(transferAmt);
			personalBilling.setInflowId(inflowId);
			personalBilling.setInflowType(inflowType);
			personalBilling.setOutflowId(perId);
			personalBilling.setOutflowType(CustomerType.CUST_PERSONAL.getCode());
			personalBilling.setPayWay(payWay);
			personalBillingMapper.insert(personalBilling);
			
			respMap.put("code", ResponseCode.OK.getCode());
			respMap.put("msg", ResponseCode.OK.getMessage());
			
		}else{
			respMap.put("code", ResponseCode.VERIFY_ACC_AMT.getCode());
			respMap.put("msg", ResponseCode.VERIFY_ACC_AMT.getMessage());
		}
		
		log.info("个人账户入金   响应参数：{}",respMap);
		return respMap;
	}
	
	/**
	 * 个人账户出金
	 * 入参：perId、accType、outAmt
	 */
	public Map<String, Object> withdraw(Map<String, Object> param){
		log.info("个人账户出金   请求参数：{}",param);
		Map<String, Object> respMap = new HashMap<String, Object>();
		
		String perId = (String) param.get("perId");
		String platformId = (String) param.get("platformId");
		String accType = (String) param.get("accType");
		String orderNo = (String) param.get("orderNo");
		String orderType = (String) param.get("orderType");
		String transferAmtStr = (String) param.get("transferAmt");
		
		String outflowId = (String) param.get("outflowId");
		String outflowType = (String) param.get("outflowType");
		
		BigDecimal transferAmt = new BigDecimal(transferAmtStr);
		
		Map<String, Object> reqBalMap = new HashMap<String, Object>();
		reqBalMap.put("perId", perId);
		reqBalMap.put("platformId", platformId);
		reqBalMap.put("accType", accType);
		Map<String, Object> openAccMap = openAccount(reqBalMap);
		if (!ResponseCode.OK.getCode().equals(openAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openAccMap);
			return openAccMap;
		}
		PersonalAccount personalAccount = (PersonalAccount) openAccMap.get("personalAccount");
		
		
		if ("00".equals(personalAccount.getAccountStatus())) {
			// 个人转出账户正常
			boolean flag = MD5.verify(personalAccount.getAccBalance().toString(), personalAccount.getChecksum(), balanceSaltValue, "utf-8");
			if (flag) {
				if (personalAccount.getAccBalance().compareTo(transferAmt) >= 0) {
					personalAccount.setAccBalance(personalAccount.getAccBalance().subtract(transferAmt));
					personalAccount.setChecksum(MD5.sign(personalAccount.getAccBalance().toString(), balanceSaltValue, "utf-8"));
					personalAccount.setUpdatetime(new Timestamp(System.currentTimeMillis()));
					personalAccountMapper.updateByPrimaryKey(personalAccount);
					
					PersonalAccountJournal personalAccountJournal = new PersonalAccountJournal();
					String perJournalId = String.valueOf(SnowFlake.getId());
					personalAccountJournal.setJournalId(perJournalId);
					personalAccountJournal.setAccId(personalAccount.getAccId());
					personalAccountJournal.setPlatformId(platformId);
					personalAccountJournal.setOrderNo(orderNo);
					personalAccountJournal.setPerId(perId);
					personalAccountJournal.setAccType(accType);
					personalAccountJournal.setInOutFlag("2");//往账
					personalAccountJournal.setTradeAmt(transferAmt);
					personalAccountJournal.setTradeType(orderType);
					personalAccountJournal.setCreatetime(new Timestamp(System.currentTimeMillis()));
					personalAccountJournalMapper.insert(personalAccountJournal);
					
					PersonalBilling personalBilling = new PersonalBilling();
					String billId = String.valueOf(SnowFlake.getId());
					personalBilling.setBillId(billId);
					personalBilling.setPlatformId(platformId);
					personalBilling.setPerId(perId);
					personalBilling.setAccJournalId(perJournalId);
					personalBilling.setOrderNo(orderNo);
					personalBilling.setBillType(orderType);
					personalBilling.setInOutFlag("2");// 往账
					personalBilling.setTranAmt(transferAmt);
					personalBilling.setInflowId(perId);
					personalBilling.setInflowType(CustomerType.CUST_PERSONAL.getCode());
					personalBilling.setOutflowId(outflowId);
					personalBilling.setOutflowType(outflowType);
					personalBilling.setPayWay(accType);
					personalBillingMapper.insert(personalBilling);
					
					respMap.put("code", ResponseCode.OK.getCode());
					respMap.put("msg", ResponseCode.OK.getMessage());
				} else {
					respMap.put("code", ResponseCode.ACC_BALANCE_INSUFFICIENT.getCode());
					respMap.put("msg", ResponseCode.ACC_BALANCE_INSUFFICIENT.getMessage());
				}
			}else{
				respMap.put("code", ResponseCode.VERIFY_ACC_AMT.getCode());
				respMap.put("msg", ResponseCode.VERIFY_ACC_AMT.getMessage());
			}
		} else if("01".equals(personalAccount.getAccountStatus())) {
			// 个人转出账户被冻结
			respMap.put("code", ResponseCode.PER_ACC_FREEZE.getCode());
			respMap.put("msg", ResponseCode.PER_ACC_FREEZE.getMessage());
		}
		
		log.info("个人账户出金   响应参数：{}",respMap);
		return respMap;
	}
	
	/**
	 * 系统内个人转账
	 * 转账给商家 intoCustomerAccType:00
	 * 转账给个人 intoCustomerAccType:01
	 * 转账给平台 intoCustomerAccType:02
	 * 1、判断转出账户是否存在
	 * 2、判断账户余额是否大于转出金额
	 * 3、判断转入用户是否存在
	 * 4、判断转入用户账户类型是企业还是个人
	 * 5、判断转入账户是否存在
	 * 6、转出账户余额减少，转入账户余额增多
	 * 入参：perId、accType、intoMobile（转入账户手机号）、intoCustomerAccType（转入客户类型）、transferAmt（交易金额）
	 */
	public Map<String, Object> transfer(Map<String, Object> param) {
		log.info("系统内个人转账   请求参数：{}", param);
		Map<String, Object> respMap = new HashMap<String, Object>();
		String perId = (String) param.get("perId");
		String intoId = (String) param.get("intoId");
		String platformId = (String) param.get("platformId");
		String intoCustomerAccType = (String) param.get("intoCustomerAccType");
		String intoAccType = (String) param.get("intoAccType");
		String outAccType = (String) param.get("outAccType");
		String transferAmtStr = (String) param.get("transferAmt");
		BigDecimal transferAmt = new BigDecimal(transferAmtStr);
		String orderNo = (String) param.get("orderNo");
		String orderType = (String) param.get("orderType");
		
		Map<String, Object> reqBalMap = new HashMap<String, Object>();
		reqBalMap.put("perId", perId);
		reqBalMap.put("platformId", platformId);
		reqBalMap.put("accType", outAccType);
		Map<String, Object> openAccMap = openAccount(reqBalMap);
		if (!ResponseCode.OK.getCode().equals(openAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openAccMap);
			return openAccMap;
		}
		PersonalAccount personalAccount = (PersonalAccount) openAccMap.get("personalAccount");
		
		if ("00".equals(personalAccount.getAccountStatus())) {
			// 个人转出账户正常
			boolean flag = MD5.verify(personalAccount.getAccBalance().toString(), personalAccount.getChecksum(), balanceSaltValue, "utf-8");
			if (flag) {
				if (personalAccount.getAccBalance().compareTo(transferAmt) >= 0) {
					// 转账给企业或平台
					if ("00".equals(intoCustomerAccType) || "02".equals(intoCustomerAccType)) {
						
						Map<String, Object> reqMerBalMap = new HashMap<String, Object>();
						reqMerBalMap.put("merId", intoId);
						reqMerBalMap.put("platformId", platformId);
						reqMerBalMap.put("accType", intoAccType);
						Map<String, Object> openMerAccMap = merchantAccountBiz.openAccount(reqMerBalMap);
						if (!ResponseCode.OK.getCode().equals(openMerAccMap.get("code"))) {
							log.info("客户账户开户 异常参数：{}",openMerAccMap);
							return openMerAccMap;
						}
						MerchantAccount merchantAccount = (MerchantAccount) openAccMap.get("merchantAccount");
						
						Map<String, Object> reqOutMap = new HashMap<String, Object>();
						reqOutMap.put("perId", perId);
						reqOutMap.put("platformId", platformId);
						reqOutMap.put("accType", outAccType);
						reqOutMap.put("orderNo", orderNo);
						reqOutMap.put("orderType", orderType);
						reqOutMap.put("transferAmt", transferAmtStr);
						reqOutMap.put("outflowId", intoId);
						reqOutMap.put("outflowType", CustomerType.CUST_MERCHANT.getCode());
						respMap = withdraw(reqOutMap);
						if (ResponseCode.OK.getCode().equals(respMap.get("code"))) {
							merchantAccount.setAccBalance(merchantAccount.getAccBalance().add(transferAmt));
							merchantAccount.setChecksum(MD5.sign(merchantAccount.getAccBalance().toString(),balanceSaltValue, "utf-8"));
							merchantAccountMapper.updateByPrimaryKey(merchantAccount);
							
							MerchantAccountJournal merchantAccountJournal = new MerchantAccountJournal();
							String journalId = String.valueOf(SnowFlake.getId());
							merchantAccountJournal.setJournalId(journalId);
							merchantAccountJournal.setAccId(merchantAccount.getAccId());
							merchantAccountJournal.setPlatformId(platformId);
							merchantAccountJournal.setOrderNo(orderNo);;
							merchantAccountJournal.setMerId(intoId);
							merchantAccountJournal.setAccType(intoAccType);
							merchantAccountJournal.setInOutFlag("1");//来账
							merchantAccountJournal.setTradeAmt(transferAmt);
							merchantAccountJournal.setTradeType(orderType);
							merchantAccountJournal.setCreatetime(new Timestamp(System.currentTimeMillis()));
							merchantAccountJournalMapper.insert(merchantAccountJournal);
							
							respMap.put("code", ResponseCode.OK.getCode());
							respMap.put("msg", ResponseCode.OK.getMessage());
						}
						
					} else if ("01".equals(intoCustomerAccType)) {
						
						Map<String, Object> reqPerBalMap = new HashMap<String, Object>();
						reqPerBalMap.put("perId", intoId);
						reqPerBalMap.put("platformId", platformId);
						reqPerBalMap.put("accType", intoAccType);
						Map<String, Object> openPerAccMap = openAccount(reqPerBalMap);
						if (!ResponseCode.OK.getCode().equals(openPerAccMap.get("code"))) {
							log.info("客户账户开户 异常参数：{}",openPerAccMap);
							return openPerAccMap;
						}
						PersonalAccount intoPersonalAccount = (PersonalAccount) openPerAccMap.get("personalAccount");
						
						Map<String, Object> reqOutMap = new HashMap<String, Object>();
						reqOutMap.put("perId", perId);
						reqOutMap.put("platformId", platformId);
						reqOutMap.put("accType", outAccType);
						reqOutMap.put("orderNo", orderNo);
						reqOutMap.put("orderType", orderType);
						reqOutMap.put("transferAmt", transferAmtStr);
						reqOutMap.put("outflowId", intoId);
						reqOutMap.put("outflowType", CustomerType.CUST_PERSONAL.getCode());
						respMap = withdraw(reqOutMap);
						if (ResponseCode.OK.getCode().equals(respMap.get("code"))) {
							Map<String, Object> reqIntoMap = new HashMap<String, Object>();
							reqIntoMap.put("perId", intoId);
							reqIntoMap.put("platformId", platformId);
							reqIntoMap.put("accType", intoAccType);
							reqIntoMap.put("orderNo", orderNo);
							reqIntoMap.put("orderType", orderType);
							reqIntoMap.put("transferAmt", transferAmtStr);
							reqIntoMap.put("payWay", outAccType);
							reqIntoMap.put("inflowId", perId);
							reqIntoMap.put("inflowType", CustomerType.CUST_PERSONAL.getCode());
							respMap = deposit(reqIntoMap);
						}
					}
				} else {
					respMap.put("code", ResponseCode.ACC_BALANCE_INSUFFICIENT.getCode());
					respMap.put("msg", ResponseCode.ACC_BALANCE_INSUFFICIENT.getMessage());
				}
			} else {
				respMap.put("code", ResponseCode.VERIFY_ACC_AMT.getCode());
				respMap.put("msg", ResponseCode.VERIFY_ACC_AMT.getMessage());
			}
		} else if ("01".equals(personalAccount.getAccountStatus())) {
			// 个人转出账户被冻结
			respMap.put("code", ResponseCode.PER_ACC_FREEZE.getCode());
			respMap.put("msg", ResponseCode.PER_ACC_FREEZE.getMessage());
		}
		log.info("系统内个人转账   响应参数：{}", respMap);
		return respMap;
	}
	
	/**
	 * 个人资金冻结（冻结余额）
	 * @author centerroot
	 * @time 创建时间:2018年6月1日上午9:57:08
	 * @param param
	 * @return
	 */
	public Map<String, Object> freeze(Map<String, Object> param){
		log.info("个人资金冻结   请求参数：{}",param);
		Map<String, Object> respMap = new HashMap<String, Object>();
		String perId = (String) param.get("perId");
		String freezeAmtStr = (String) param.get("freezeAmt");
		BigDecimal freezeAmt = new BigDecimal(freezeAmtStr);
		String platformId = (String) param.get("platformId");
		String orderNo = (String) param.get("orderNo");
		String orderType = (String) param.get("orderType");
		String taskId = (String) param.get("taskId");
		
		Map<String, Object> reqBalMap = new HashMap<String, Object>();
		reqBalMap.put("perId", perId);
		reqBalMap.put("platformId", platformId);
		reqBalMap.put("accType", AccountType.ACC_BALANCE.getCode());
		Map<String, Object> openPerAccMap = openAccount(reqBalMap);
		if (!ResponseCode.OK.getCode().equals(openPerAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openPerAccMap);
			return openPerAccMap;
		}
		PersonalAccount personalAccount = (PersonalAccount) openPerAccMap.get("personalAccount");
		
		Map<String, Object> reqFreezeMap = new HashMap<String, Object>();
		reqFreezeMap.put("perId", perId);
		reqFreezeMap.put("platformId", platformId);
		reqFreezeMap.put("accType", AccountType.ACC_FREEZE.getCode());
		Map<String, Object> openFreezeAccMap = openAccount(reqFreezeMap);
		if (!ResponseCode.OK.getCode().equals(openFreezeAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openFreezeAccMap);
			return openFreezeAccMap;
		}
		PersonalAccount personalAccountFreeze = (PersonalAccount) openFreezeAccMap.get("personalAccount");
		
		boolean accBalFlag = MD5.verify(personalAccount.getAccBalance().toString(), personalAccount.getChecksum(), balanceSaltValue, "utf-8");
		boolean accFreezeflag = MD5.verify(personalAccountFreeze.getAccBalance().toString(), personalAccountFreeze.getChecksum(), balanceSaltValue, "utf-8");
		
		if (accBalFlag && accFreezeflag) {
			
			if ("00".equals(personalAccount.getAccountStatus())) {
				// 账户正常
				if (personalAccount.getAccBalance().compareTo(freezeAmt) >= 0) {
					
					
					Map<String, Object> reqOutMap = new HashMap<String, Object>();
					reqOutMap.put("perId", perId);
					reqOutMap.put("platformId", platformId);
					reqOutMap.put("accType", AccountType.ACC_BALANCE.getCode());
					reqOutMap.put("orderNo", orderNo);
					reqOutMap.put("orderType", orderType);
					reqOutMap.put("transferAmt", freezeAmtStr);
					respMap = withdraw(reqOutMap);
					if (ResponseCode.OK.getCode().equals(respMap.get("code"))) {
						Map<String, Object> reqIntoMap = new HashMap<String, Object>();
						reqIntoMap.put("perId", perId);
						reqIntoMap.put("platformId", platformId);
						reqIntoMap.put("accType", AccountType.ACC_FREEZE.getCode());
						reqIntoMap.put("orderNo", orderNo);
						reqIntoMap.put("orderType", orderType);
						reqIntoMap.put("transferAmt", freezeAmtStr);
						respMap = deposit(reqIntoMap);
						
						if (ResponseCode.OK.getCode().equals(respMap.get("code"))) {
							FreezeJournal freezeJournal = new FreezeJournal();
							String freezeId = String.valueOf(SnowFlake.getId());
							freezeJournal.setJournalId(freezeId);
							freezeJournal.setOrderNo(orderNo);
							freezeJournal.setOrderType(orderType);
							freezeJournal.setConType("1");
							freezeJournal.setConAccId(personalAccount.getAccId());
							freezeJournal.setBalance(freezeAmt);
							freezeJournal.setFreezeType("1");
							freezeJournal.setStatus("1");
							freezeJournal.setCreatetime(new Timestamp(System.currentTimeMillis()));
							freezeJournalMapper.insert(freezeJournal);
							
							respMap.put("freezeId", freezeId);
						}
						
					}
					
				} else {
					respMap.put("code", ResponseCode.ACC_BALANCE_INSUFFICIENT.getCode());
					respMap.put("msg", ResponseCode.ACC_BALANCE_INSUFFICIENT.getMessage());
				}
			} else if("01".equals(personalAccount.getAccountStatus())) {
				// 账户被冻结
				respMap.put("code", ResponseCode.PER_ACC_FREEZE.getCode());
				respMap.put("msg", ResponseCode.PER_ACC_FREEZE.getMessage());
			}

		}else{
			respMap.put("code", ResponseCode.VERIFY_ACC_AMT.getCode());
			respMap.put("msg", ResponseCode.VERIFY_ACC_AMT.getMessage());
		}
		
		log.info("个人资金冻结   响应参数：{}",respMap);
		return respMap;
	}
	
	/**
	 * 个人资金解冻（可部分解冻）
	 * @author centerroot
	 * @time 创建时间:2018年6月1日下午1:47:50
	 * @param param
	 * @return
	 */
	public Map<String, Object> unfreeze(Map<String, Object> param){
		log.info("个人资金解冻（可部分解冻）   请求参数：{}",param);
		Map<String, Object> respMap = new HashMap<String, Object>();
		String perId = (String) param.get("perId");
		String freezeId = (String) param.get("freezeId");
		String unfreezeAmtStr = (String) param.get("unfreezeAmt");
		BigDecimal unfreezeAmt = new BigDecimal(unfreezeAmtStr);
		String platformId = (String) param.get("platformId");
		String orderNo = (String) param.get("orderNo");
		String orderType = (String) param.get("orderType");
		
		Map<String, Object> reqBalMap = new HashMap<String, Object>();
		reqBalMap.put("perId", perId);
		reqBalMap.put("platformId", platformId);
		reqBalMap.put("accType", AccountType.ACC_BALANCE.getCode());
		Map<String, Object> openAccMap = openAccount(reqBalMap);
		if (!ResponseCode.OK.getCode().equals(openAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openAccMap);
			return openAccMap;
		}
		PersonalAccount personalAccount = (PersonalAccount) openAccMap.get("personalAccount");
		
		Map<String, Object> reqFreezeMap = new HashMap<String, Object>();
		reqFreezeMap.put("perId", perId);
		reqFreezeMap.put("platformId", platformId);
		reqFreezeMap.put("accType", AccountType.ACC_FREEZE.getCode());
		Map<String, Object> openFreezeAccMap = openAccount(reqFreezeMap);
		if (!ResponseCode.OK.getCode().equals(openFreezeAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openFreezeAccMap);
			return openFreezeAccMap;
		}
		PersonalAccount personalAccountFreeze = (PersonalAccount) openFreezeAccMap.get("personalAccount");
		
		boolean accBalFlag = MD5.verify(personalAccount.getAccBalance().toString(), personalAccount.getChecksum(), balanceSaltValue, "utf-8");
		boolean accFreezeflag = MD5.verify(personalAccountFreeze.getAccBalance().toString(), personalAccountFreeze.getChecksum(), balanceSaltValue, "utf-8");
		
		if (accBalFlag && accFreezeflag) {
			if (personalAccountFreeze.getAccBalance().compareTo(unfreezeAmt) >= 0) {
				// 冻结账户余额大于解冻金额
				if ("00".equals(personalAccount.getAccountStatus())) {
					// 账户正常
					FreezeJournal freezeJournal = freezeJournalMapper.selectByPrimaryKey(freezeId);
					if (null != freezeJournal) {
						BigDecimal unfreezeTotal = BigDecimal.ZERO;
						UnfreezeJournal unfreezeJournalReq = new UnfreezeJournal();
						unfreezeJournalReq.setFreezeId(freezeId);
						List<UnfreezeJournal> unfreezeJournals = unfreezeJournalMapper.select(unfreezeJournalReq);
						if (null != unfreezeJournals && unfreezeJournals.size() > 0) {
							for (int i = 0; i < unfreezeJournals.size(); i++) {
								unfreezeTotal = unfreezeTotal.add(unfreezeJournals.get(i).getBalance());
							}
						}
						unfreezeTotal = unfreezeTotal.add(unfreezeAmt);
						if (unfreezeTotal.compareTo(freezeJournal.getBalance()) <= 0) {
							
							Map<String, Object> reqOutMap = new HashMap<String, Object>();
							reqOutMap.put("perId", perId);
							reqOutMap.put("platformId", platformId);
							reqOutMap.put("accType", AccountType.ACC_FREEZE.getCode());
							reqOutMap.put("orderNo", orderNo);
							reqOutMap.put("orderType", orderType);
							reqOutMap.put("transferAmt", unfreezeAmt);
							respMap = withdraw(reqOutMap);
							if (ResponseCode.OK.getCode().equals(respMap.get("code"))) {
								Map<String, Object> reqIntoMap = new HashMap<String, Object>();
								reqIntoMap.put("perId", perId);
								reqIntoMap.put("platformId", platformId);
								reqIntoMap.put("accType", AccountType.ACC_BALANCE.getCode());
								reqIntoMap.put("orderNo", orderNo);
								reqIntoMap.put("orderType", orderType);
								reqIntoMap.put("transferAmt", unfreezeAmt);
								respMap = deposit(reqIntoMap);
								
								if (ResponseCode.OK.getCode().equals(respMap.get("code"))) {
									UnfreezeJournal unfreezeJournal = new UnfreezeJournal();
									String unfreezeId = String.valueOf(SnowFlake.getId());
									unfreezeJournal.setJournalId(unfreezeId);
									unfreezeJournal.setOrderNo(orderNo);
									unfreezeJournal.setOrderType(orderType);
									unfreezeJournal.setFreezeId(freezeId);
									unfreezeJournal.setBalance(unfreezeAmt);
									unfreezeJournal.setCreatetime(new Timestamp(System.currentTimeMillis()));
									unfreezeJournalMapper.insert(unfreezeJournal);
									
									if (unfreezeTotal.compareTo(freezeJournal.getBalance()) < 0) {
										freezeJournal.setStatus("2"); // 部分解冻
										freezeJournalMapper.updateByPrimaryKey(freezeJournal);
									}else if (unfreezeTotal.compareTo(freezeJournal.getBalance()) == 0) {
										freezeJournal.setStatus("3"); // 已解冻
										freezeJournalMapper.updateByPrimaryKey(freezeJournal);
									}
								}
							}
						} else {
							respMap.put("code", ResponseCode.FREEZE_UNFREEZE_AMT_INCONSISTEND.getCode());
							respMap.put("msg", ResponseCode.FREEZE_UNFREEZE_AMT_INCONSISTEND.getMessage());
						}
					} else {
						respMap.put("code", ResponseCode.FREEZE_ID_NOTEXIST.getCode());
						respMap.put("msg", ResponseCode.FREEZE_ID_NOTEXIST.getMessage());
					}
					
				} else if("01".equals(personalAccount.getAccountStatus())) {
					// 账户被冻结
					respMap.put("code", ResponseCode.PER_ACC_FREEZE.getCode());
					respMap.put("msg", ResponseCode.PER_ACC_FREEZE.getMessage());
				}
			}else{
				respMap.put("code", ResponseCode.ACC_BALANCE_INSUFFICIENT.getCode());
				respMap.put("msg", ResponseCode.ACC_BALANCE_INSUFFICIENT.getMessage());
				log.info("商户资金解冻（可部分解冻）【冻结账户余额不足】   响应参数：{}",respMap);
			}
		}else{
			respMap.put("code", ResponseCode.VERIFY_ACC_AMT.getCode());
			respMap.put("msg", ResponseCode.VERIFY_ACC_AMT.getMessage());
		}
		
		log.info("个人资金解冻（可部分解冻）   响应参数：{}",respMap);
		return respMap;
	}
	
	
	/**
	 * 提现（解冻并出账）
	 * @author centerroot
	 * @time 创建时间:2018年6月5日下午1:43:16
	 * @param param
	 * @return
	 */
	public Map<String, Object> unfreezeDebit(Map<String, Object> param){
		log.info("提现（解冻并出账）   请求参数：{}",param);
		Map<String, Object> respMap = new HashMap<String, Object>();
		String perId = (String) param.get("perId");
		String freezeId = (String) param.get("freezeId");
		String unfreezeAmtStr = (String) param.get("unfreezeAmt");
		String withdrawFeeStr = (String) param.get("withdrawFee");
		BigDecimal unfreezeAmt = new BigDecimal(unfreezeAmtStr);
		BigDecimal withdrawFee = new BigDecimal(withdrawFeeStr);
		String platformId = (String) param.get("platformId");
		String orderNo = (String) param.get("orderNo");
		String orderType = (String) param.get("orderType");
		
		Customer customerRequest = new Customer();
		customerRequest.setPlatformId(platformId);
		customerRequest.setCustomerType("00"); // 平台
		Customer customer = customerMapper.selectOne(customerRequest);
		if (null == customer) {
			respMap.put("code", ResponseCode.CUST_NOTEXIST.getCode());
			respMap.put("msg", ResponseCode.CUST_NOTEXIST.getMessage());
			log.info("提现（解冻并出账）   平台信息不存在");
		}
		
		Map<String, Object> reqPlatMap = new HashMap<String, Object>();
		reqPlatMap.put("merId", customer.getMerId());
		reqPlatMap.put("platformId", platformId);
		reqPlatMap.put("accType", AccountType.ACC_BALANCE.getCode());
		Map<String, Object> respPlatMap = openAccount(reqPlatMap);
		if (!ResponseCode.OK.getCode().equals(respPlatMap.get("code"))) {
			log.info("个人账户开户 异常参数：{}",respPlatMap);
			return respPlatMap;
		}
		MerchantAccount PlatAccount = (MerchantAccount) respPlatMap.get("merchantAccount");
		
		
		Map<String, Object> reqMap = new HashMap<String, Object>();
		reqMap.put("perId", perId);
		reqMap.put("platformId", platformId);
		reqMap.put("accType", AccountType.ACC_BALANCE.getCode());
		Map<String, Object> openAccMap = openAccount(reqMap);
		if (!ResponseCode.OK.getCode().equals(openAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openAccMap);
			return openAccMap;
		}
		PersonalAccount personalAccount = (PersonalAccount) openAccMap.get("personalAccount");
		
		Map<String, Object> reqFreezeMap = new HashMap<String, Object>();
		reqFreezeMap.put("perId", perId);
		reqFreezeMap.put("platformId", platformId);
		reqFreezeMap.put("accType", AccountType.ACC_FREEZE.getCode());
		Map<String, Object> openFreezeAccMap = openAccount(reqFreezeMap);
		if (!ResponseCode.OK.getCode().equals(openFreezeAccMap.get("code"))) {
			log.info("客户账户开户 异常参数：{}",openFreezeAccMap);
			return openFreezeAccMap;
		}
		PersonalAccount personalAccountFreeze = (PersonalAccount) openFreezeAccMap.get("personalAccount");
		
		boolean accFreezeflag = MD5.verify(personalAccountFreeze.getAccBalance().toString(), personalAccountFreeze.getChecksum(), balanceSaltValue, "utf-8");
		
		if (accFreezeflag) {
			if (personalAccountFreeze.getAccBalance().compareTo(unfreezeAmt) >= 0) {
				// 账户正常
				FreezeJournal freezeJournal = freezeJournalMapper.selectByPrimaryKey(freezeId);
				if (null != freezeJournal) {
					BigDecimal unfreezeTotal = BigDecimal.ZERO;
					UnfreezeJournal unfreezeJournalReq = new UnfreezeJournal();
					unfreezeJournalReq.setFreezeId(freezeId);
					List<UnfreezeJournal> unfreezeJournals = unfreezeJournalMapper.select(unfreezeJournalReq);
					if (null != unfreezeJournals && unfreezeJournals.size() > 0) {
						for (int i = 0; i < unfreezeJournals.size(); i++) {
							unfreezeTotal = unfreezeTotal.add(unfreezeJournals.get(i).getBalance());
						}
					}
					unfreezeTotal = unfreezeTotal.add(unfreezeAmt);
					if (unfreezeTotal.compareTo(freezeJournal.getBalance()) <= 0) {
						
						// 解冻提现金额
						personalAccountFreeze.setAccBalance(personalAccountFreeze.getAccBalance().subtract(unfreezeAmt));
						personalAccountFreeze.setChecksum(MD5.sign(personalAccountFreeze.getAccBalance().toString(), balanceSaltValue, "utf-8"));
						personalAccountMapper.updateByPrimaryKey(personalAccountFreeze);
						
						// 手续费入平台余额账户
						PlatAccount.setAccBalance(PlatAccount.getAccBalance().add(withdrawFee));
						PlatAccount.setChecksum(MD5.sign(PlatAccount.getAccBalance().toString(), balanceSaltValue, "utf-8"));
						merchantAccountMapper.updateByPrimaryKey(PlatAccount);
						
						// 记录平台账户交易流水
						MerchantAccountJournal intoMerchantAccountJournal = new MerchantAccountJournal();
						String intoJournalId = String.valueOf(SnowFlake.getId());
						intoMerchantAccountJournal.setJournalId(intoJournalId);
						intoMerchantAccountJournal.setAccId(PlatAccount.getAccId());
						intoMerchantAccountJournal.setPlatformId(platformId);
						intoMerchantAccountJournal.setOrderNo(orderNo);;
						intoMerchantAccountJournal.setMerId(PlatAccount.getMerId());
						intoMerchantAccountJournal.setAccType(PlatAccount.getAccType());
						intoMerchantAccountJournal.setInOutFlag("1");//来账
						intoMerchantAccountJournal.setTradeAmt(withdrawFee);
						intoMerchantAccountJournal.setTradeType(orderType);
						intoMerchantAccountJournal.setCreatetime(new Timestamp(System.currentTimeMillis()));
						merchantAccountJournalMapper.insert(intoMerchantAccountJournal);
						
						// 记录个人账户交易流水
						PersonalAccountJournal personalAccountJournal = new PersonalAccountJournal();
						String journalId = String.valueOf(SnowFlake.getId());
						personalAccountJournal.setJournalId(journalId);
						personalAccountJournal.setAccId(personalAccount.getAccId());
						personalAccountJournal.setPlatformId(platformId);
						personalAccountJournal.setOrderNo(orderNo);
						personalAccountJournal.setPerId(perId);
						personalAccountJournal.setAccType(AccountType.ACC_BALANCE.getCode());
						personalAccountJournal.setInOutFlag("2");//往账
						personalAccountJournal.setTradeAmt(unfreezeAmt);
						personalAccountJournal.setTradeType(orderType);
						personalAccountJournal.setCreatetime(new Timestamp(System.currentTimeMillis()));
						personalAccountJournalMapper.insert(personalAccountJournal);
						
						// 记录个人账单记录
						PersonalBilling personalBilling = new PersonalBilling();
						String billId = String.valueOf(SnowFlake.getId());
						personalBilling.setBillId(billId);
						personalBilling.setPlatformId(platformId);
						personalBilling.setPerId(perId);
						personalBilling.setAccJournalId(journalId);
						personalBilling.setOrderNo(orderNo);
						personalBilling.setBillType(orderType);
						personalBilling.setInOutFlag("2");// 往账
						personalBilling.setTranAmt(unfreezeAmt);
						personalBilling.setInflowId(perId);
						personalBilling.setInflowType(CustomerType.CUST_PERSONAL.getCode());
//						personalBilling.setOutflowId(perId);
//						personalBilling.setOutflowType(CustomerType.CUST_PERSONAL.getCode());
						personalBilling.setPayWay(AccountType.ACC_BALANCE.getCode());
						personalBillingMapper.insert(personalBilling);
						
						// 记录解冻交易流水
						UnfreezeJournal unfreezeJournal = new UnfreezeJournal();
						String unfreezeId = String.valueOf(SnowFlake.getId());
						unfreezeJournal.setJournalId(unfreezeId);
						unfreezeJournal.setOrderNo(orderNo);
						unfreezeJournal.setOrderType(orderType);
						unfreezeJournal.setFreezeId(freezeId);
						unfreezeJournal.setBalance(unfreezeAmt);
						unfreezeJournal.setCreatetime(new Timestamp(System.currentTimeMillis()));
						unfreezeJournalMapper.insert(unfreezeJournal);
						
						if (unfreezeTotal.compareTo(freezeJournal.getBalance()) < 0) {
							freezeJournal.setStatus("2"); // 部分解冻
							freezeJournalMapper.updateByPrimaryKey(freezeJournal);
						}else if (unfreezeTotal.compareTo(freezeJournal.getBalance()) == 0) {
							freezeJournal.setStatus("3"); // 已解冻
							freezeJournalMapper.updateByPrimaryKey(freezeJournal);
						}
						respMap.put("code", ResponseCode.OK.getCode());
						respMap.put("msg", ResponseCode.OK.getMessage());
						
					} else {
						respMap.put("code", ResponseCode.FREEZE_UNFREEZE_AMT_INCONSISTEND.getCode());
						respMap.put("msg", ResponseCode.FREEZE_UNFREEZE_AMT_INCONSISTEND.getMessage());
					}
				} else {
					respMap.put("code", ResponseCode.FREEZE_ID_NOTEXIST.getCode());
					respMap.put("msg", ResponseCode.FREEZE_ID_NOTEXIST.getMessage());
				}
				
			}else{
				respMap.put("code", ResponseCode.ACC_BALANCE_INSUFFICIENT.getCode());
				respMap.put("msg", ResponseCode.ACC_BALANCE_INSUFFICIENT.getMessage());
				log.info("提现（解冻并出账）【冻结账户余额不足】   响应参数：{}",respMap);
			}
		}else{
			respMap.put("code", ResponseCode.VERIFY_ACC_AMT.getCode());
			respMap.put("msg", ResponseCode.VERIFY_ACC_AMT.getMessage());
		}
		
		log.info("提现（解冻并出账）   响应参数：{}",respMap);
		return respMap;
	}
	
	
	
	
	/**
	 * 查询个人账户
	 * @param map
	 * @return
	 */
	public List<PersonalAccount> queryPersonalAccountInfos(Map<String, Object> map) {
		log.info("查询个人账户参数。。。{}"+map);
		List<PersonalAccount> list = personalAccountMapper.queryPersonalAccountInfo(map);
		log.info("查询个人账户。。。{}"+list);
		return list;
	}
	
	
	/**
	 * 修改冻结状态
	 * @param map
	 * @return
	 */
	public Map<String, Object> updateAccountStatus(Map<String, Object> map) {
		log.info("修改冻结状态参数。。。{}"+map);
		personalAccountMapper.updateAccountStatus(map);
		Map<String, Object> respMap = new HashMap<>();
		respMap.put("code", ResponseCode.OK.getCode());
		respMap.put("msg", ResponseCode.OK.getMessage());
		return respMap;
	}
	
	/**
	 * 查询用户账户信息
	 * @author centerroot
	 * @time 创建时间:2018年6月4日上午11:49:39
	 * @param map
	 * @return
	 */
	public Map<String, Object> queryPersonalAccountInfo(Map<String, Object> map) {
		log.info("查询用户账户信息。。。请求参数：{}",map);
		Map<String, Object> respMap = new HashMap<>();
		PersonalAccount personalAccountReq = new PersonalAccount();
		personalAccountReq.setPerId((String) map.get("perId"));
		personalAccountReq.setAccType(AccountType.ACC_BALANCE.getCode());
		PersonalAccount personalAccountResp = personalAccountMapper.selectOne(personalAccountReq);
		if (null != personalAccountResp && personalAccountResp.getAccBalance() != null) {
			log.info("根据用户编号查询用户余额账户信息结果：{}",EntityUtils.beanToMap(personalAccountResp));
			respMap.put("accountBalance", personalAccountResp.getAccBalance().toString());
		} else {
			respMap.put("accountBalance", "0");
		}
		respMap.put("code", ResponseCode.OK.getCode());
		respMap.put("msg", ResponseCode.OK.getMessage());
		log.info("查询用户账户信息。。。响应参数：{}",respMap);
		return respMap;
	}
	



}